﻿namespace Leetcode.N1096;

public class Solution
{
    public IList<string> BraceExpansionII(string expression)
    {
        int i = 0;
        return this.BraceExpansion(expression, ref i).OrderBy(_=>_).ToList();
    }

    private ISet<string> BraceExpansion(string expression, ref int index)
    {
        ISet<string> result = new HashSet<string>();
        ISet<string> segments = new HashSet<string>();
        for (; index < expression.Length; index++)
        {
            switch (expression[index])
            {
                case '{':
                    index++;
                    segments = this.Join(segments, this.BraceExpansion(expression, ref index));
                    break;
                case ',':
                    this.Merge(result, segments);
                    segments.Clear();
                    break;
                case '}':
                    this.Merge(result, segments);
                    segments.Clear();
                    return result;
                default:
                    var word = this.ReadWord(expression, ref index);
                    segments = this.Join(segments, word);
                    break;
            }
        }
        return this.Merge(result, segments);
    }

    private ISet<string> Merge(ISet<string> s1, ISet<string> s2)
    {
        foreach (var item in s2)
        {
            s1.Add(item);
        }
        return s1;
    }
    private ISet<string> Join(ISet<string> s1, ISet<string> s2)
    {
        var set = new HashSet<string>();
        if (s1.Count == 0)
        {
            foreach (var item2 in s2)
            {
                set.Add(item2);
            }
        }
        else
        {
            foreach (var item in s1)
            {
                foreach (var item2 in s2)
                {
                    set.Add(item + item2);
                }
            }
        }

        return set;
    }

    private ISet<string> Join(ISet<string> s1, string word)
    {
        var ans = new HashSet<string>();
        if (s1.Count > 0)
        {
            foreach (var item in s1)
            {
                ans.Add(item + word);
            }
        }
        else
        {
            ans.Add(word);
        }

        return ans;

    }

    private string ReadWord(string s, ref int index)
    {
        var fromIndex = index;
        var toIndex = fromIndex;
        for (int i = index + 1; i < s.Length; i++)
        {
            if (s[i] == '{' || s[i] != '}' || s[i] != ',')
            {
                break;
            }
            toIndex = i;
            index = i;
        }
        return s.Substring(fromIndex, toIndex - fromIndex + 1);
    }
}